#ifndef PARSERTHREAD_H
#define PARSERTHREAD_H

#include <wx/dynarray.h>
#include <wx/event.h>
#include <wx/string.h>
#include <wx/thread.h>

#include <queue>
#include <vector>

#include <M_Code_threadpool.h>
#include <filemanager.h>
#include <logmanager.h>
#include "cclogger.h"
#include "tokenizer.h"
#include "token.h"
#include "tokentree.h"


struct NameSpace {
  wxString Name;
  int StartLine;
  int EndLine;
};

typedef std::vector<NameSpace> NameSpaceVec;

class ParserBase;

struct ParserThreadOptions {
  ParserThreadOptions() :

    useBuffer( false ),
    fileOfBuffer(),
    parentIdxOfBuffer( -1 ),
    initLineOfBuffer( 1 ),
    bufferSkipBlocks( false ),
    bufferSkipOuterBlocks( false ),
    isTemp( false ),

    followLocalIncludes( true ),
    followGlobalIncludes( true ),
    wantPreprocessor( true ),
    parseComplexMacros( true ),
    platformCheck( true ),

    handleFunctions( true ),
    handleVars( true ),
    handleClasses( true ),
    handleEnums( true ),
    handleTypedefs( true ),

    storeDocumentation( false ),

    loader( nullptr ) {}
  bool        useBuffer;

  wxString    fileOfBuffer;
  int         parentIdxOfBuffer;
  int         initLineOfBuffer;
  bool        bufferSkipBlocks;
  bool        bufferSkipOuterBlocks;
  bool        isTemp;
  bool        followLocalIncludes;
  bool        followGlobalIncludes;
  bool        wantPreprocessor;
  bool        parseComplexMacros;
  bool        platformCheck;
  bool        handleFunctions;
  bool        handleVars;
  bool        handleClasses;
  bool        handleEnums;
  bool        handleTypedefs;
  bool        storeDocumentation;
  LoaderBase* loader;
};

class ParserThread : public cbThreadedTask {
  public:
    ParserThread( ParserBase*          parent,
                  const wxString&      bufferOrFilename,
                  bool                 isLocal,
                  ParserThreadOptions& parserThreadOptions,
                  TokenTree*           tokenTree );


    virtual ~ParserThread();
    bool Parse();
    bool ParseBufferForNamespaces( const wxString& buffer, NameSpaceVec& result );
    bool ParseBufferForUsingNamespace( const wxString& buffer, wxArrayString& result );

    wxString GetFilename() { return m_Buffer; }
  protected:
    enum EClassType { ctStructure = 0, ctClass = 1, ctUnion = 3 };
    int Execute() {
      CC_LOCKER_TRACK_TT_MTX_LOCK( s_TokenTreeMutex )
      bool success = Parse();
      CC_LOCKER_TRACK_TT_MTX_UNLOCK( s_TokenTreeMutex )
      return success ? 0 : 1;
    }

    wxChar SkipToOneOfChars( const wxString& chars, bool supportNesting = false, bool singleCharToken = true );
    void DoParse();
    void SkipBlock();
    void SkipAngleBraces();
    void HandleIncludes();
    void HandleNamespace();
    void HandleClass( EClassType ct );
    void HandleFunction( wxString& name, bool isOperator = false, bool isPointer = false );
    void HandleForLoopArguments();
    void HandleConditionalArguments();
    void HandleEnum();
    bool CalcEnumExpression( Token* tokenParent, long& result, wxString& peek );
    void HandleTypedef();
    bool ReadVarNames();
    bool ReadClsNames( wxString& ancestor );
    wxString ReadAngleBrackets();
    Token* DoAddToken( TokenKind       kind,
                       const wxString& name,
                       int             line,
                       int             implLineStart = 0,
                       int             implLineEnd = 0,
                       const wxString& args = wxEmptyString,
                       bool            isOperator = false,
                       bool            isImpl = false );

    wxString GetTokenBaseType();

  private:

    bool InitTokenizer();
    Token* TokenExists( const wxString& name, const Token* parent = 0, short int kindMask = 0xFFFF );
    Token* TokenExists( const wxString& name, const wxString& baseArgs, const Token* parent, TokenKind kind );
    Token* FindTokenFromQueue( std::queue<wxString>& q,
                               Token*                parent = 0,
                               bool                  createIfNotExist = false,
                               Token*                parentIfCreated = 0 );


    bool GetBaseArgs( const wxString & args, wxString& baseArgs );


    void GetTemplateArgs();


    void ResolveTemplateArgs( Token* newToken );


    wxArrayString GetTemplateArgArray( const wxString& templateArgs, bool remove_gt_lt, bool add_last );


    void SplitTemplateFormalParameters( const wxString& templateArgs, wxArrayString& formals );


    void SplitTemplateActualParameters( const wxString& templateArgs, wxArrayString& actuals );


    bool ResolveTemplateMap( const wxString& typeStr, const wxArrayString& actuals,
                             std::map<wxString, wxString>& results );


    void RemoveTemplateArgs( const wxString& expr, wxString &expNoArgs, wxString &templateArgs );


    bool IsStillAlive( const wxString& funcInfo );


    void  RefineAnonymousTypeToken( short int typeMask, wxString alise );


    Tokenizer            m_Tokenizer;


    ParserBase*          m_Parent;


    TokenTree*           m_TokenTree;


    Token*               m_LastParent;


    TokenScope           m_LastScope;


    wxString             m_Filename;


    unsigned int         m_FileSize;


    unsigned int         m_FileIdx;


    bool                 m_IsLocal;


    wxString             m_Str;


    wxString             m_LastToken;


    ParserThreadOptions  m_Options;


    std::queue<wxString> m_EncounteredNamespaces;


    std::queue<wxString> m_EncounteredTypeNamespaces;


    TokenIdxSet          m_UsedNamespacesIds;


    wxString             m_LastUnnamedTokenName;


    bool                 m_ParsingTypedef;


    wxString             m_Buffer;


    wxString             m_PointerOrRef;


    wxString             m_TemplateArgument;

    size_t               m_StructUnionUnnamedCount;

    size_t               m_EnumUnnamedCount;
};

#endif
